﻿using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace SpriteSheetsFabric.Wpf
{
    /// <summary>
    /// Contains extension methods for FrameworkElement
    /// </summary>
    public static class VisualExtension
    {
        /// <summary>
        /// Renders a Visual within a custom bound
        /// </summary>
        /// <param name="source">The source to render</param>
        /// <param name="targetBound">The target bounds.</param>
        /// <param name="dpiX">dpiX value</param>
        /// <param name="dpiY">dpiY value</param>
        /// <param name="autoLayout">if set to <c>true</c> [do a render cycle].</param>
        /// <returns>
        /// The BitmapSource if generation succeeded
        /// </returns>
        public static BitmapSource RenderIntoBitmap(this Visual source, Rect targetBound, double dpiX = 96d, double dpiY = 96d, bool autoLayout = false)
        {
            // Defensive coding
            if (source == null)
            {
                return null;
            }

            // Initialize Target Bitmap
            var targetBitmap = new RenderTargetBitmap(
                (int)(targetBound.Width * dpiX / 96.0),
                (int)(targetBound.Height * dpiY / 96.0),
                dpiX,
                dpiY,
                PixelFormats.Pbgra32);

            // Do a Render cycle
            FrameworkElement fram;
            if (autoLayout && ((fram = source as FrameworkElement) != null) && !fram.IsLoaded)
            {
                fram.Measure(targetBound.Size);
                fram.Arrange(targetBound);
            }

            // Render to Visual Brush
            var drawingVisual = new DrawingVisual();
            using (var drawingContext = drawingVisual.RenderOpen())
            {
                var brush = new VisualBrush(source);
                drawingContext.DrawRectangle(brush, null, new Rect(new Point(), targetBound.Size));
            }

            targetBitmap.Render(drawingVisual);

            return targetBitmap; 
        }

        /// <summary>
        /// Renders a Visual within its bound
        /// </summary>
        /// <param name="source">The source.</param>
        /// <param name="dpiX">The dpi X.</param>
        /// <param name="dpiY">The dpi Y.</param>
        /// <param name="autoLayout">if set to <c>true</c> [do a render cycle].</param>
        /// <returns></returns>
        public static BitmapSource RenderIntoBitmap(this Visual source, double dpiX = 96d, double dpiY = 96d, bool autoLayout = false)
        {
            var bounds = VisualTreeHelper.GetDescendantBounds(source).OrDefault();
            return RenderIntoBitmap(source, bounds, dpiX, dpiY, autoLayout);
        }

        public static Rect OrDefault(this Rect bounds, double defaultX = 0, double defaultY = 0, double defaultWidth = 800, double defaultHeight = 600)
        {
            return new Rect(
                double.IsInfinity(bounds.X) ? defaultX : bounds.X,
                double.IsInfinity(bounds.Y) ? defaultY : bounds.Y,
                double.IsInfinity(bounds.Width) ? defaultWidth : bounds.Width,
                double.IsInfinity(bounds.Height) ? defaultHeight : bounds.Height);
        }
    }
}
